package com.qf.shiro;

import com.hazelcast.util.StringUtil;
import com.qf.pojo.DtsAdmin;
import com.qf.service.DtsAdminService;
import com.qf.service.DtsPermissionService;
import com.qf.service.DtsRoleService;
import com.qf.util.bcrypt.BCryptPasswordEncoder;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * @author Cc
 * @version 1.0
 *      自定义 Realm 认证和授权方法
 */

public class AdminAuthorizingRealm extends AuthorizingRealm {

    private  final Logger logger =  LoggerFactory.getLogger(AdminAuthorizingRealm.class);

    @Autowired
    private DtsAdminService adminService;

    @Autowired
    private DtsRoleService roleService;

    @Autowired
    private DtsPermissionService permissionService;

    /**
     * 授权方法
     * @param principals the primary identifying principals of the AuthorizationInfo that should be retrieved.
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        logger.info("「管理模块」用户登录 -----> 授权管理: {}", username);
        List<DtsAdmin> adminList = adminService.findAdmin(username);
        Assert.state(adminList.size() < 2, "不止一个用户哦");

        //判断是否已经查询到数据
        if (adminList.size()==0){
            logger.error("未找到"+username+"的信息");
            throw  new AuthenticationException("认证失败,未找到"+username+"的信息");
        }

        //找到当前需要验证的用户
        DtsAdmin admin = adminList.get(0);
        // 获取用户名称对应的角色的ids字段
        Integer[] ids = admin.getRoleIds();
        logger.info("「管理模块」用户登录 -----> ids: {}", Arrays.toString(ids));

        // 根据ids去dts_role表当中查询出对应的角色名称
        Collection<String> roleName = roleService.queryByIds(ids);
        logger.info("「管理模块」获取的角色名称 ----->   role name: {}", roleName);


        //根据ids去dts_permission表当中查询出权限信息
        Set<String> permission = permissionService.queryByRoleIds(ids);
        logger.info("「管理模块」获取的权限信息 -----> permission name: {}", permission);


        //给shiro添加数据
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRoles(roleName);
        simpleAuthorizationInfo.addStringPermissions(permission);

        return simpleAuthorizationInfo;

    }

    /**
     *  认证方法
     * @param token the authentication token containing the user's principal and credentials.
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //1. 先拿到用户名和密码
        String username = (String) token.getPrincipal();
             //密码需要转换成 char[] 类型 才可以
        String password = new String((char[])token.getCredentials());
        //1.2 对前端传进来的用户名和密码做一下校验
        if (StringUtil.isNullOrEmpty(username)) {
            throw  new RuntimeException("用户名不能为空");
        }
        if (StringUtil.isNullOrEmpty(password)){
            throw new RuntimeException("密码不能为空");
        }
        //2.根据用户名去查出来一个用户对象
        List<DtsAdmin> admin = adminService.findAdmin(username);
        if (admin == null) {
            throw new UnknownAccountException("用户不存在");
        }
        //3.判断数据库中是否有用户的信息
        if (admin.size()==0){
            logger.error("未找到"+username+"的信息");
            throw  new AuthenticationException("认证失败,未找到"+username+"的信息");
        }
        //4.验证密码是否正确
        //找到当前要验证的用户
        DtsAdmin admin1= admin.get(0);
        //拿前端传进来的密码和数据库的密码做对比
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(password,admin1.getPassword())) {
            logger.error("未找到"+username+"的信息");
            throw  new UnknownAccountException("用户不存在");
        }
        //校验账户是否启用
        if(admin1.getDeleted() == true){
            logger.error("帐号"+username+"未启用");
            throw new UnknownAccountException("用户未启用");
        }

        //封装数据 返回
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,password,this.getName());
        return info;
    }
}
